﻿using System;
using System.Threading.Tasks;
using K9Nano.Dependency;
using K9Nano.Runtime;

namespace K9Nano.Configuration
{
    public class SettingManager : ISettingManager, IScopedDependency
    {
        protected readonly ISettingStore SettingStore;
        protected readonly ISessionContext SessionContext;
        protected readonly ISettingDefinitionManager SettingDefinitionManager;

        public SettingManager(ISettingStore settingStore, ISessionContext sessionContext, ISettingDefinitionManager settingDefinitionManager)
        {
            SettingStore = settingStore;
            SessionContext = sessionContext;
            SettingDefinitionManager = settingDefinitionManager;
        }

        public virtual ValueTask<string> GetSettingValueAsync(string name)
        {
            return GetSettingValueAsync(name, SessionContext.TenantId, SessionContext.UserId);
        }

        public virtual async ValueTask<string> GetSettingValueAsync(string name, Guid? tenantId, Guid? userId)
        {
            var setting = await SettingStore.GetSettingOrNullAsync(tenantId, userId, name);
            if (setting == null)
            {
                return GetDefaultSettingValue(name, tenantId, userId);
            }

            return setting.Value;
        }

        public virtual ValueTask ChangeSettingAsync(string name, string value)
        {
            return ChangeSettingAsync(name, value, SessionContext.TenantId, SessionContext.UserId);
        }

        public virtual async ValueTask ChangeSettingAsync(string name, string value, Guid? tenantId, Guid? userId)
        {
            await SettingStore.CreateOrUpdateAsync(new SettingInfo(tenantId, userId, name, value));
        }

        protected virtual string GetDefaultSettingValue(string name, Guid? tenantId = null, Guid? userId = null)
        {
            var settingDefinition = SettingDefinitionManager.GetSettingDefinition(name);

            if (userId.HasValue)
            {
                // Get for user if defined
                if (settingDefinition.Scopes.HasFlag(ESettingScopes.User) || settingDefinition.IsInherited)
                {
                    return settingDefinition.DefaultValue;
                }
            }
            else if (tenantId.HasValue)
            {
                // Get for tenant if defined
                if (settingDefinition.Scopes.HasFlag(ESettingScopes.Tenant)
                    || (settingDefinition.Scopes.HasFlag(ESettingScopes.Application) && settingDefinition.IsInherited))
                {
                    return settingDefinition.DefaultValue;
                }
            }
            else if (settingDefinition.Scopes.HasFlag(ESettingScopes.Application))
            {
                // Get for application if defined
                return settingDefinition.DefaultValue;
            }

            return null;
        }
    }
}